﻿#pragma once

//实现vtk渲染窗口的功能
#include <vector>
#include <map>
#include <string>

#include <vtkOrientationMarkerWidget.h>
#include "vtkSmartPointer.h"
#include "vtkWeakPointer.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkCamera.h"
#include "vtkCallbackCommand.h"
#include <vtkActor.h>
#include <vtkAssembly.h>
#include <vtkInformation.h>
#include <vtkInformationDoubleVectorKey.h>
#include <vtkCallbackCommand.h>
#include <vtkInteractorStyle.h>
#include <vtkSetGet.h>
#include <vtkPropPicker.h>
#include <vtkFollower.h>



class MyVtkOrientationMarkerWidget;
class MyVtkAxesActorCallbackBase;
class MyVtkAxesActorCallbackHover;
class MyVtkAxesActorCallbackPick;



//自定义的vtkAxesActor
class MyVtkAxesActor: public vtkAssembly
{
public:
    MyVtkAxesActor();
    ~MyVtkAxesActor();

    static MyVtkAxesActor* New();

public:
    void SetControledRenderer(vtkRenderer* pRenderer);
    vtkRenderer* GetControledRenderer() const;

    void SetRenderWindowInteractor(vtkRenderWindowInteractor* pRenderWindowInteractor);
    void SetAxesMarkerWidget(MyVtkOrientationMarkerWidget* pAxesMarkerWidget);
    MyVtkOrientationMarkerWidget* GetAxesMarkerWidget() const;

    void AddActor(vtkActor* actor);
    void GetActors(std::vector<vtkActor*>& actors);

    void AddLabel(vtkSmartPointer<vtkFollower> label);

    //create axes
    void CereateAxesArrow();
    void CereateAxesLabel();

    //create face
    void CereateFace();
    void CereateEdgeFace();
    void CereateVertexFace();

    //tools
    vtkSmartPointer<vtkActor> CreateArrowActor(const int& direction, double* color);
    vtkSmartPointer<vtkActor> CreateFaceActor(double* origin, double* point1, double* point2, double* color, double* viewup);
    vtkSmartPointer<vtkActor> CreateTriangleActor(double* origin, double* point1, double* point2, double* color, double* viewup);
    void FaceAddTexture(vtkActor* actor, const char* textureFile); //ActorAddTexture

    //getinfo
    vtkInformationDoubleVectorKey* GetDirectionInfoKey()
    {
        return m_pDirectionInfoKey;
    }


private:
    vtkRenderer* m_pContoledRenderer = nullptr;
    vtkRenderWindowInteractor* m_pRenderWindowInteractor = nullptr;
    MyVtkOrientationMarkerWidget* m_pAxesMarkerWidget = nullptr;
    std::vector<vtkActor*> m_vecActors;
    std::vector<vtkSmartPointer<vtkFollower>> m_vecLabels;

    vtkInformationDoubleVectorKey* m_pDirectionInfoKey = nullptr;

    enum EDirection
    {
        E_DIRECTION_X_PLUS,
        E_DIRECTION_Y_PLUS,
        E_DIRECTION_Z_PLUS,
        E_DIRECTION_X_MINUS,
        E_DIRECTION_Y_MINUS,
        E_DIRECTION_Z_MINUS
    };

    double m_edgeWidgth = 0.15;
    double m_faceWidgth = 0.6;
    double m_boxGap = 0.05;

    std::map<int, std::string> m_AxesFaceTextureIconMap
    {
        { E_DIRECTION_X_PLUS, "../icon/AxesIcon/My_Axes_XPlus.png" },
        { E_DIRECTION_Y_PLUS, "../icon/AxesIcon/My_Axes_YPlus.png" },
        { E_DIRECTION_Z_PLUS, "../icon/AxesIcon/My_Axes_ZPlus.png" },
        { E_DIRECTION_X_MINUS, "../icon/AxesIcon/My_Axes_XMinus.png" },
        { E_DIRECTION_Y_MINUS, "../icon/AxesIcon/My_Axes_YMinus.png" },
        { E_DIRECTION_Z_MINUS, "../icon/AxesIcon/My_Axes_ZMinus.png" }
    };
};




//自定义的vtkOrientationMarkerWidget  
class MyVtkOrientationMarkerWidget: public vtkOrientationMarkerWidget
{
public:
    static MyVtkOrientationMarkerWidget* New()
    {
        return new MyVtkOrientationMarkerWidget();
    }

    MyVtkOrientationMarkerWidget()
    {
    }

    vtkRenderer* GetRenderer() const
    {
        return this->Renderer;
    }

    void SetAxesMarker(MyVtkAxesActor* pAxesActor)
    {
        m_pAxesActor = pAxesActor;

        if(!m_pAxesActor)
        {
            return;
        }

        m_pAxesActorPicker = vtkSmartPointer<vtkPropPicker>::New();
        m_pAxesActorPicker->SetPickFromList(true);
        std::vector<vtkActor*> actorsList;
        m_pAxesActor->GetActors(actorsList);
        for(auto actor : actorsList)
        {
            m_pAxesActorPicker->AddPickList(actor);
        }
    }


protected:

    void OnLeftButtonDown() override
    {
        if(!JugeInsideViewport())
        {
            return;
        }


        if(!m_pAxesActor)
        {
            return;
        }

        auto pAxesControledRenderer = m_pAxesActor->GetControledRenderer();
        if(!pAxesControledRenderer)
        {
            return;
        }

        //pick actor
        if(!m_pAxesActorPicker)
        {
            return;
        }

        auto position = m_pInteractor->GetEventPosition();
        m_pAxesActorPicker->Pick(position[0], position[1], 0, m_pRenderer);
        vtkActor* actorPicked = m_pAxesActorPicker->GetActor();

        if(!actorPicked)
        {
            return;
        }

        //get direction
        auto actorInfo = actorPicked->GetProperty()->GetInformation();
        double* direction = actorInfo->Get(m_pAxesActor->GetDirectionInfoKey());
        if(!direction)
        {
            return;
        }

        //set camera direction
        double* oldCameraBoundes = pAxesControledRenderer->ComputeVisiblePropBounds();//记录当前视角下可见的actor的边界
        auto camera = pAxesControledRenderer->GetActiveCamera();
        camera->SetPosition(direction[0], direction[1], direction[2]);
        camera->SetFocalPoint(0, 0, 0);
        camera->SetViewUp(direction[3], direction[4], direction[5]);

        pAxesControledRenderer->ResetCamera(oldCameraBoundes);//恢复旧的边界
        m_pInteractor->Render();//渲染
    }

    void OnLeftButtonUp() override
    {
        this->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr);

        if(!JugeInsideViewport())
        {
            if(m_pLastHoverActor)
            {
                m_pLastHoverActor->GetProperty()->SetColor(m_pLastHoverActorColor);
                m_pInteractor->Render();
                m_pLastHoverActor = nullptr;
            }
            return;
        }
    }

    void OnMouseMove() override
    {
        if(!JugeInsideViewport())
        {
            if(m_pLastHoverActor)
            {
                m_pLastHoverActor->GetProperty()->SetColor(m_pLastHoverActorColor);
                m_pInteractor->Render();
                m_pLastHoverActor = nullptr;
            }
            return;
        }

        //pick actor
        if(!m_pAxesActorPicker)
        {
            return;
        }

        auto position = m_pInteractor->GetEventPosition();
        m_pAxesActorPicker->Pick(position[0], position[1], 0, m_pRenderer);
        vtkActor* actorPicked = m_pAxesActorPicker->GetActor();

        //reset last hover actor color
        if(m_pLastHoverActor == actorPicked)
        {
            return;
        }
        else if(m_pLastHoverActor)
        {
            m_pLastHoverActor->GetProperty()->SetColor(m_pLastHoverActorColor);
            m_pInteractor->Render();
        }

        //set hover color
        m_pLastHoverActor = actorPicked;
        if(!actorPicked)
        {
            return;
        }

        auto color = actorPicked->GetProperty()->GetColor();//记录当前actor的颜色
        m_pLastHoverActorColor[0] = color[0];
        m_pLastHoverActorColor[1] = color[1];
        m_pLastHoverActorColor[2] = color[2];

        actorPicked->GetProperty()->SetColor(1, 0, 1);//set hover color to red
        m_pInteractor->Render();//渲染
    }

    bool JugeInsideViewport()
    {
        m_pRenderer = this->Renderer;
        m_pInteractor = this->Interactor;

        if(!m_pInteractor || !m_pRenderer)
        {
            return false;
        }

        // We're only here if we are enabled
        int* eventPos = m_pInteractor->GetEventPosition();
        int x = eventPos[0];
        int y = eventPos[1];

        // are we over the widget?
        double vp[4];
        m_pRenderer->GetViewport(vp);
        m_pRenderer->NormalizedDisplayToDisplay(vp[0], vp[1]);
        m_pRenderer->NormalizedDisplayToDisplay(vp[2], vp[3]);

        int pos1[2] = {static_cast<int>(vp[0]), static_cast<int>(vp[1])};
        int pos2[2] = {static_cast<int>(vp[2]), static_cast<int>(vp[3])};

        // flag that we are attempting to adjust or move the outline
        if(x <= (pos1[0]) || (pos2[0]) <= x ||
           y <= (pos1[1]) || (pos2[1]) <= y)
        {
            return false;
        }

        return true;
    }


private:
    MyVtkAxesActor* m_pAxesActor = nullptr;
    vtkActor* m_pLastHoverActor = nullptr;
    double m_pLastHoverActorColor[3] = {0, 0, 0};
    vtkRenderer* m_pRenderer = nullptr;
    vtkRenderWindowInteractor* m_pInteractor = nullptr;
    vtkSmartPointer<vtkPropPicker> m_pAxesActorPicker = nullptr;
};




//回调函数基类
class MyVtkAxesActorCallbackBase: public vtkCallbackCommand
{
public:
    MyVtkAxesActorCallbackBase()
    {
    }

    virtual ~MyVtkAxesActorCallbackBase()
    {
    };

    static MyVtkAxesActorCallbackBase* New()
    {
        return new MyVtkAxesActorCallbackBase;
    }

    void SetAxesActor(MyVtkAxesActor* pAxesActor)
    {
        m_pAxesActor = pAxesActor;
        SetMarkerWidget(m_pAxesActor->GetAxesMarkerWidget());
    }

    void SetMarkerWidget(MyVtkOrientationMarkerWidget* pMarkerWidget)
    {
        m_pMarkerWidget = pMarkerWidget;
    }

    bool GetEnabled(double position[2]) const
    {
        bool enabled = true;
        double* viewport = m_pMarkerWidget->GetViewport();

    }

protected:
    MyVtkAxesActor* m_pAxesActor = nullptr;
    MyVtkOrientationMarkerWidget* m_pMarkerWidget = nullptr;
};


//鼠标悬停回调函数
class MyVtkAxesActorCallbackHover: public MyVtkAxesActorCallbackBase
{
public:
    MyVtkAxesActorCallbackHover()
    {
    }

    static MyVtkAxesActorCallbackHover* New()
    {
        return new MyVtkAxesActorCallbackHover;
    }

    void Execute(vtkObject* caller, unsigned long, void*) override
    {
        vtkRenderWindowInteractor* pInteractor = static_cast<vtkRenderWindowInteractor*>(caller);
        if(!pInteractor)
        {
            return;
        }

        //pick actor
        vtkNew<vtkPropPicker> picker;
        picker->SetPickFromList(true);
        std::vector<vtkActor*> actorsList;
        m_pAxesActor->GetActors(actorsList);
        for(auto actor : actorsList)
        {
            picker->AddPickList(actor);
        }

        //pick actor
        auto position = pInteractor->GetEventPosition();
        picker->Pick(position[0], position[1], 0, m_pMarkerWidget->GetRenderer());
        vtkActor* actor = picker->GetActor();

        //reset last hover actor color
        if(m_pLastHoverActor == actor)
        {
            return;
        }
        else if(m_pLastHoverActor)
        {
            m_pLastHoverActor->GetProperty()->SetColor(m_pLastHoverActorColor);
            pInteractor->GetRenderWindow()->Render();
        }

        //set hover color
        m_pLastHoverActor = actor;
        if(!actor)
        {
            return;
        }

        auto color = actor->GetProperty()->GetColor();//记录当前actor的颜色
        m_pLastHoverActorColor[0] = color[0];
        m_pLastHoverActorColor[1] = color[1];
        m_pLastHoverActorColor[2] = color[2];

        actor->GetProperty()->SetColor(1, 0, 1);//set hover color to red
        pInteractor->GetRenderWindow()->Render();//渲染
    }


private:
    vtkActor* m_pLastHoverActor = nullptr;
    double m_pLastHoverActorColor[3] = {0, 0, 0};
};


//鼠标点击回调函数
class MyVtkAxesActorCallbackPick: public MyVtkAxesActorCallbackBase
{
public:
    MyVtkAxesActorCallbackPick()
    {
    }

    static MyVtkAxesActorCallbackPick* New()
    {
        return new MyVtkAxesActorCallbackPick;
    }

    void Execute(vtkObject* caller, unsigned long, void*) override
    {
        vtkRenderWindowInteractor* pInteractor = static_cast<vtkRenderWindowInteractor*>(caller);
        if(!pInteractor)
        {
            return;
        }

        auto pAxesControledRenderer = m_pAxesActor->GetControledRenderer();
        if(!pAxesControledRenderer)
        {
            return;
        }

        //pick actor
        vtkNew<vtkPropPicker> picker;
        picker->SetPickFromList(true);
        std::vector<vtkActor*> actorsList;
        m_pAxesActor->GetActors(actorsList);
        for(auto actor : actorsList)
        {
            picker->AddPickList(actor);
        }

        auto position = pInteractor->GetEventPosition();
        picker->Pick(position[0], position[1], 0, m_pMarkerWidget->GetRenderer());
        vtkActor* actor = picker->GetActor();

        if(!actor)
        {
            return;
        }

        //get direction
        auto actorInfo = actor->GetProperty()->GetInformation();
        double* direction = actorInfo->Get(m_pAxesActor->GetDirectionInfoKey());
        if(!direction)
        {
            return;
        }

        //set camera direction
        double* oldCameraBoundes = pAxesControledRenderer->ComputeVisiblePropBounds();//记录当前视角下可见的actor的边界
        auto camera = pAxesControledRenderer->GetActiveCamera();
        camera->SetPosition(direction[0], direction[1], direction[2]);
        camera->SetFocalPoint(0, 0, 0);
        camera->SetViewUp(direction[3], direction[4], direction[5]);

        pAxesControledRenderer->ResetCamera(oldCameraBoundes);//恢复旧的边界
        pInteractor->GetRenderWindow()->Render();//渲染
    }

};